package com.alibaba.citrus.ots.b2b.trade.order.facade.service;

import com.alibaba.citrus.ots.b2b.trade.order.functions.order.entity.OrderWriteEntity;
import com.alibaba.citrus.ots.b2b.trade.order.functions.order.factory.OrderWriteFactory;
import com.alibaba.citrus.ots.b2b.trade.order.functions.orderLine.entity.OrderLineWriteEntity;
import com.alibaba.citrus.ots.b2b.trade.order.functions.orderLine.factory.OrderLineWriteFactory;
import com.alibaba.citrus.ots.b2b.trade.order.repository.OrderLineWriteRepository;
import com.alibaba.citrus.ots.b2b.trade.order.repository.OrderQueryRepository;
import com.alibaba.citrus.ots.b2b.trade.order.repository.request.UpdateFeaturesReq;
import com.alibaba.citrus.ots.common.annotation.FacadeInvoker;
import com.alibaba.citrus.ots.common.annotation.FieldColMapping;
import com.alibaba.citrus.ots.common.annotation.OperaterLog;
import com.alibaba.citrus.ots.common.constant.SaleOrderConstants;
import com.alibaba.citrus.ots.common.exception.FacadeException;
import com.alibaba.citrus.ots.common.log.ModuleEnum;
import com.alibaba.citrus.ots.common.log.ParamTypeEnum;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.cz.base.tool.log.model.OpLogModel;
import com.alibaba.cz.base.tool.log.model.OperateType;
import com.alibaba.cz.base.tool.log.model.OperatorType;
import com.alibaba.fastjson.JSON;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.otsb2btradecenter.api.orderlinewrite.service.OrderLineWriteService;
import com.epoch.app.otsb2btradecenter.dto.request.OrderLineModifyRequest;
import com.epoch.app.otsb2btradecenter.dto.request.OrderLineRemoveRequest;
import com.epoch.app.otsb2btradecenter.dto.request.OrderLineSaveRequest;
import com.epoch.app.otsb2btradecenter.dto.request.OrderQueryRequest;
import com.epoch.app.otsb2btradecenter.model.dto.FeaturesUpdateRequest;
import com.epoch.app.otsb2btradecenter.model.dto.OrderLineRemoveResponse;
import com.epoch.app.otsb2btradecenter.model.dto.OrderLineSaveResponse;
import com.epoch.app.otsb2btradecenter.model.dto.SubFeaturesRequest;
import com.epoch.app.otsb2btradecenter.sdo.OrderLineSDO;
import com.epoch.app.otsb2btradecenter.sdo.OrderSDO;
import com.google.common.collect.Maps;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Primary
public class OrderLineWriteServiceImpl implements OrderLineWriteService {
    @Resource
    private  OrderLineWriteRepository orderLineWriteRepository;
    @Resource
    OrderQueryRepository orderQueryRepository;

    private static final Log log = Log.getLogger(OrderLineWriteServiceImpl.class);

    @Override
    public Result<OrderLineRemoveResponse> remove(OrderLineRemoveRequest request) {
        List<String> ids = new ArrayList<>();
        List<OrderLineWriteEntity> orderLineWriteEntities = OrderLineWriteFactory.removeOrderLine(request);
        for (OrderLineWriteEntity orderLineWriteEntity : orderLineWriteEntities) {
            String id = orderLineWriteEntity.remove();
            if (id != null) {
                ids.add(id);
            }
            OpLogModel.OpLogModelBuilder<String> builder = OpLogModel.builder();
            OpLogModel<String> opLogModel = builder.build();
            opLogModel.setModuleName(ModuleEnum.SALES.getModuleName());
            opLogModel.setModuleId(String.valueOf(ModuleEnum.SALES.getModuleId()));
            opLogModel.setObjectId(id);
            opLogModel.setObjectName("id");
            opLogModel.setOperateType(OperateType.DELETE.getOperateType());
            opLogModel.setOperatorType(OperatorType.USER.getOperatorType());
            log.asyncMonitorObjectChangeV2(opLogModel);
        }
        return Result.success(OrderLineRemoveResponse.builder().ids(ids).build());
    }

    @Override
    public Result<OrderLineSaveResponse> save(OrderLineSaveRequest request) {
        if (request.getBaseInfo() != null) {
            OrderWriteEntity orderWriteEntity = OrderWriteFactory.saveSaleOrder(request.getBaseInfo());
            String id = orderWriteEntity.save();

            OpLogModel.OpLogModelBuilder<String> builder = OpLogModel.builder();
            OpLogModel<String> opLogModel = builder.build();
            opLogModel.setModuleName(ModuleEnum.SALES.getModuleName());
            opLogModel.setModuleId(String.valueOf(ModuleEnum.SALES.getModuleId()));
            opLogModel.setObjectId(id);
            opLogModel.setObjectName("id");
            opLogModel.setOperateType(OperateType.DELETE.getOperateType());
            opLogModel.setOperatorType(OperatorType.USER.getOperatorType());
            log.asyncMonitorObjectChangeV2(opLogModel);
        }
        List<String> ids = new ArrayList<>();
        List<OrderLineWriteEntity> orderLineWriteEntities = OrderLineWriteFactory.saveOrderLine(request);
        for (OrderLineWriteEntity orderLineWriteEntity : orderLineWriteEntities) {
            String id = orderLineWriteEntity.save();
            ids.add(id);
            OpLogModel.OpLogModelBuilder<String> builder = OpLogModel.builder();
            OpLogModel<String> opLogModel = builder.build();
            opLogModel.setModuleName(ModuleEnum.FORECAST_SALES.getModuleName());
            opLogModel.setModuleId(String.valueOf(ModuleEnum.FORECAST_SALES.getModuleId()));
            opLogModel.setObjectId(id);
            opLogModel.setObjectName("id");
            opLogModel.setOperateType(OperateType.CREATE.getOperateType());
            opLogModel.setOperatorType(OperatorType.USER.getOperatorType());
            log.asyncMonitorObjectChangeV2(opLogModel);
        }
        return Result.success(OrderLineSaveResponse.builder().ids(ids).build());
    }

    @Override
    @FacadeInvoker(errorCode = "OTS-05-001-10-16-003")
    @OperaterLog(operateType = OperateType.EDIT, operatorType = OperatorType.USER, module = ModuleEnum.FORECAST_SALES, choiceParam = ParamTypeEnum.INPUT_PARAM)
    public Result<Void> modify(@FieldColMapping(fieldName = "id", fieldValue = "")OrderLineModifyRequest request) {
        OrderLineWriteEntity orderLineWriteEntity = OrderLineWriteFactory.modifyOrderLine(request);
        Boolean result = orderLineWriteEntity.modify();
        if (result != true) {
            throw new FacadeException("修改订单失败");
        }
        return Result.success(null);
    }

    @Override
    @FacadeInvoker
    public Result<Void> updateFeatures(FeaturesUpdateRequest featuresUpdateRequest) {
        log.info("OrderLineWriteServiceImpl.updateFeatures:FeaturesUpdateRequest = " + JSON.toJSONString(featuresUpdateRequest));

        Map<String, String> mainOrderFeaturesToUpdate = MapUtils.emptyIfNull(featuresUpdateRequest.getMainOrderFeaturesToUpdate());
        List<String> mainOrderFeaturesToDelete = new ArrayList<>();
        if(featuresUpdateRequest.getMainOrderFeaturesToDelete() != null){
            mainOrderFeaturesToDelete = featuresUpdateRequest.getMainOrderFeaturesToDelete().keySet().stream().collect(Collectors.toList());
        }
        Map<String, SubFeaturesRequest> subOrderFeaturesMapToUpdate = MapUtils.emptyIfNull(featuresUpdateRequest.getSubOrderFeaturesToUpdate());
        Map<String, SubFeaturesRequest> subOrderFeaturesMapToDelete = MapUtils.emptyIfNull(featuresUpdateRequest.getSubOrderFeaturesToDelete());

        Map<String, Map<String, String>> subOrderFeaturesToUpdate = new HashMap<>();
        Map<String,Integer> subOrderVersionMap = new HashMap<>();
        subOrderFeaturesMapToUpdate.forEach((k, v) -> {
            subOrderFeaturesToUpdate.put(k, v.getSubOrderFeaturesToUpdate());
            if(v.getSyncVersion() != null){
                subOrderVersionMap.put(k,v.getSyncVersion());
            }
//          subOrderFeaturesToDelete.put(k, (Set<String>) v.getSubOrderFeaturesToDelete());
        });

        Map<String, List<String>> subOrderFeaturesToDelete= new HashMap<>();
        Map<String, String> subOrderFeaturesToDeleteDelivery= new HashMap<>();
        subOrderFeaturesMapToDelete.forEach((k, v) -> {
            subOrderFeaturesToDelete.put(k,v.getSubOrderFeaturesToDelete());
            Map<String, String> bizFeatures = v.getBizFeatures();
            if (MapUtils.isNotEmpty(bizFeatures)){
                subOrderFeaturesToDeleteDelivery.put(k,bizFeatures.getOrDefault(SaleOrderConstants.DELIVERY_DELETE,Boolean.FALSE.toString()));
            }

        });

        boolean subOrderNeedUpdate = !subOrderFeaturesToUpdate.isEmpty() || !subOrderFeaturesToDelete.isEmpty();

        OrderQueryRequest queryRequest = new OrderQueryRequest();
        queryRequest.setId(featuresUpdateRequest.getMainOrderId());
        OrderSDO modifiableTradeOrderSDO = orderQueryRepository.querySingle(queryRequest);

//      Assert.notNull(modifiableTradeOrderSDO, () -> String.valueOf(new FacadeException("","")));
//        if (featuresUpdateRequest.getOrderSyncVersionToCheck() != null) {
            //校验乐观锁 todo 黔雷
//          Assert.eq(modifiableTradeOrderSDO.getSyncVersion(), updateRequest.getOrderSyncVersionToCheck(), () -> ErrorMessages.dataAlreadChanged());
//        }

        /**
         * repo层的更新入参
         */
        UpdateFeaturesReq updateFeaturesReq = new UpdateFeaturesReq();
        updateFeaturesReq.setOrderId(featuresUpdateRequest.getMainOrderId());
        updateFeaturesReq.setOrderSyncVersionToCheck(featuresUpdateRequest.getOrderSyncVersionToCheck() != null
                ? featuresUpdateRequest.getOrderSyncVersionToCheck()
                : modifiableTradeOrderSDO.getSyncVersion());

        //更新主订单的标,主订单必更新，用于做乐观锁并发控制
        if(featuresUpdateRequest.getMainOrderFeaturesToUpdate() != null || featuresUpdateRequest.getMainOrderFeaturesToDelete() != null){
            Map<String, String> mainOrderFeaturesResult = Maps.newHashMap();
            mainOrderFeaturesResult.putAll(modifiableTradeOrderSDO.getFeatures());
            if (MapUtils.isNotEmpty(mainOrderFeaturesToUpdate)){
                mainOrderFeaturesResult.putAll(mainOrderFeaturesToUpdate);
            }
            if(CollectionUtils.isNotEmpty(mainOrderFeaturesToDelete)){
                mainOrderFeaturesToDelete.forEach(mainOrderFeaturesResult::remove);
            }
            updateFeaturesReq.setMainOrderFeaturesToUpdate(mainOrderFeaturesResult);
        }


        if (subOrderNeedUpdate) {
            //需要更新子订单标
            Set<String> affectedOrderLines = mergeSets(subOrderFeaturesToUpdate.keySet(), subOrderFeaturesToDelete.keySet());

            List<OrderLineSDO> orderLineSDOS = modifiableTradeOrderSDO.getOrderLineSDOS();
            Map<String, Map<String, String>> affectedOrderLineFeatures = orderLineSDOS.stream()
                    .filter(orderLineSDO -> affectedOrderLines.contains(orderLineSDO.getId()))
                    .collect(Collectors.toMap(OrderLineSDO::getId, orderLineSDO -> new HashMap<>(orderLineSDO.getFeatures())));

            if (MapUtils.isNotEmpty(subOrderFeaturesToUpdate)) {
                subOrderFeaturesToUpdate.forEach((s, featuresToUpdate) -> {
                    Map<String, String> features = affectedOrderLineFeatures.get(s);
                    if (features != null) {
                        features.putAll(featuresToUpdate);
                    }
                });
            }
            if (MapUtils.isNotEmpty(subOrderFeaturesToDelete)) {
                subOrderFeaturesToDelete.forEach((s, featuresToDelete) -> {
                    Map<String, String> features = affectedOrderLineFeatures.get(s);
                    if (features != null) {
                        featuresToDelete.forEach(features::remove);
                        //打标 是否交货单删除 by myw
                        String deliveryDelete = subOrderFeaturesToDeleteDelivery.get(s);
                        if (StringUtils.isNotBlank(deliveryDelete)){
                            features.put(SaleOrderConstants.DELIVERY_DELETE,deliveryDelete);
                        }
                    }
                });
            }
            updateFeaturesReq.setSubOrderFeaturesToUpdate(affectedOrderLineFeatures);
            updateFeaturesReq.setSubOrderVersionMap(subOrderVersionMap);
        }

        log.info("updateFeaturesReq:" + JSON.toJSONString(updateFeaturesReq));

        boolean flag = orderLineWriteRepository.updateFeatures(updateFeaturesReq);
        if (flag){
           return Result.success(null);
        }
        throw new FacadeException("OTS-05-001-10-16-035");
    }

    private <T> Set<T> mergeSets(Set<T>... sets) {
        Set<T> resultSet = new HashSet<>();
        if (sets != null) {
            for (Set<T> set : sets) {
                if (set != null) {
                    resultSet.addAll(set);
                }
            }
        }
        return resultSet;
    }

}
